/**
 * 生成excel工具类
 */
package com.nxin.file.manage.utils;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

import com.nxin.file.manage.parse.callback.ExcelParseCallback;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.Number;
import jxl.write.WritableCellFormat;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
import jxl.write.biff.RowsExceededException;

/**
 * @author qijin
 *
 */
public class XlsUtil {

	/**
	 * 创建工作博，并根据参数生成工作表
	 * 
	 * @param out
	 *            生成文件输出流
	 * @param sheetNames
	 *            工作表名称列表
	 * @return
	 * @throws IOException
	 */
	public static WritableWorkbook createWorkbookWithSheets(OutputStream out, String[] sheetNames) throws IOException {
		if (null == out) {
			throw new XlsException("参数错误，没有可用的输出流！");
		}
		if (null == sheetNames || 0 == sheetNames.length) {
			throw new XlsException("参数错误，没有可用的工作表名称！");
		}
		// 创建工作簿
		WritableWorkbook workbook = Workbook.createWorkbook(out);
		// 创建页面
		for (int i = 0; i < sheetNames.length; i++) {
			workbook.createSheet(sheetNames[i], i);
		}

		return workbook;
	}

	/**
	 * 给指定工作表，从指定起始点开始，添加一行String格式的内容
	 * 
	 * @param sheet
	 *            需要添加单元格的工作表
	 * @param colLocNum
	 *            起始位置列序号(从0开始)
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param contentArr
	 *            需要添加行的内容数组
	 * @param cellFormat
	 *            单元格格式，为null则表示不设置格式
	 * @throws RowsExceededException
	 * @throws WriteException
	 */
	public static void fillStringLabelsForRow(WritableSheet sheet, int colLocNum, int rowLocNum, String[] contentArr,
			WritableCellFormat cellFormat) throws RowsExceededException, WriteException {
		CheckParams(sheet, colLocNum, rowLocNum, contentArr);
		if (null == cellFormat) {
			for (int i = 0; i < contentArr.length; i++) {
				sheet.addCell(new Label(colLocNum + i, rowLocNum, contentArr[i]));
			}
			return;
		}
		for (int i = 0; i < contentArr.length; i++) {
			sheet.addCell(new Label(colLocNum + i, rowLocNum, contentArr[i], cellFormat));
		}
	}

	/**
	 * 给指定工作表，从指定起始点开始，添加一行数字(double)格式的内容
	 * 
	 * @param sheet
	 *            需要添加单元格的工作表
	 * @param colLocNum
	 *            起始位置列序号(从0开始)
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param contentArr
	 *            需要添加行的内容数组
	 * @param cellFormat
	 *            单元格格式，为null则表示不设置格式
	 * @throws RowsExceededException
	 * @throws WriteException
	 */
	public static void fillNumberLabelsForRow(WritableSheet sheet, int colLocNum, int rowLocNum, double[] contentArr,
			WritableCellFormat cellFormat) throws RowsExceededException, WriteException {
		CheckParams(sheet, colLocNum, rowLocNum, contentArr);
		if (null == cellFormat) {
			for (int i = 0; i < contentArr.length; i++) {
				sheet.addCell(new Number(colLocNum + i, rowLocNum, contentArr[i]));
			}
			return;
		}
		for (int i = 0; i < contentArr.length; i++) {
			sheet.addCell(new Number(colLocNum + i, rowLocNum, contentArr[i], cellFormat));
		}
	}

	/**
	 * 给指定工作表，从指定起始点开始，添加一列String格式的内容
	 * 
	 * @param sheet
	 *            需要添加单元格的工作表
	 * @param colLocNum
	 *            起始位置列序号(从0开始)
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param contentArr
	 *            需要添加行的内容数组
	 * @param cellFormat
	 *            单元格格式，为null则表示不设置格式
	 * @return
	 * @throws RowsExceededException
	 * @throws WriteException
	 */
	public static void fillStringLabelsForColumn(WritableSheet sheet, int colLocNum, int rowLocNum, String[] contentArr,
			WritableCellFormat cellFormat) throws RowsExceededException, WriteException {
		CheckParams(sheet, colLocNum, rowLocNum, contentArr);
		if (null == cellFormat) {
			for (int i = 0; i < contentArr.length; i++) {
				sheet.addCell(new Label(colLocNum, rowLocNum + i, contentArr[i]));
			}
			return;
		}
		for (int i = 0; i < contentArr.length; i++) {
			sheet.addCell(new Label(colLocNum, rowLocNum + i, contentArr[i], cellFormat));
		}
	}

	/**
	 * 给指定工作表，从指定起始点开始，添加一列数字(double)格式的内容
	 * 
	 * @param sheet
	 *            需要添加单元格的工作表
	 * @param colLocNum
	 *            起始位置列序号(从0开始)
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param contentArr
	 *            需要添加行的内容数组
	 * @return
	 * @throws RowsExceededException
	 * @throws WriteException
	 */
	public static void fillNumberLabelsForColumn(WritableSheet sheet, int colLocNum, int rowLocNum, double[] contentArr,
			WritableCellFormat cellFormat) throws RowsExceededException, WriteException {
		CheckParams(sheet, colLocNum, rowLocNum, contentArr);
		if (null == cellFormat) {
			for (int i = 0; i < contentArr.length; i++) {
				sheet.addCell(new Number(colLocNum, rowLocNum + i, contentArr[i]));
			}
			return;
		}
		for (int i = 0; i < contentArr.length; i++) {
			sheet.addCell(new Number(colLocNum, rowLocNum + i, contentArr[i]));
		}
	}

	/**
	 * 给指定工作表，从指定起始点开始，添加一行自动格式的内容 如果给出的String有内容为数字格式，会自动转换成double格式
	 * 如果给出的内容为纯数字，但是不想作为数字处理，请在内容前加单引号'
	 * 
	 * @param sheet
	 *            需要添加单元格的工作表
	 * @param colLocNum
	 *            起始位置列序号(从0开始)
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param contentArr
	 *            需要添加行的内容数组
	 * @param cellFormat
	 *            单元格格式，为null则表示不设置格式
	 * @return
	 * @throws RowsExceededException
	 * @throws WriteException
	 */
	public static void fillAutoTransLabelsForRow(WritableSheet sheet, int colLocNum, int rowLocNum, String[] contentArr,
			WritableCellFormat cellFormat) throws RowsExceededException, WriteException {
		CheckParams(sheet, colLocNum, rowLocNum, contentArr);
		if (null == cellFormat) {
			for (int i = 0; i < contentArr.length; i++) {
				String content = contentArr[i];
				if (TextUtil.isNumber(content)) {
					sheet.addCell(new Number(colLocNum + i, rowLocNum, Double.parseDouble(content)));
					continue;
				}
				sheet.addCell(new Label(colLocNum + i, rowLocNum, content));
			}
			return;
		}
		for (int i = 0; i < contentArr.length; i++) {
			String content = contentArr[i];
			if (TextUtil.isNumber(content)) {
				sheet.addCell(new Number(colLocNum + i, rowLocNum, Double.parseDouble(content), cellFormat));
				continue;
			}
			sheet.addCell(new Label(colLocNum + i, rowLocNum, content, cellFormat));
		}
	}

	/**
	 * 检验参数是否合格
	 * 
	 * @param sheet
	 * @param colLocNum
	 * @param rowLocNum
	 * @param contentArr
	 */
	private static void CheckParams(WritableSheet sheet, int colLocNum, int rowLocNum, double[] contentArr) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > colLocNum || 0 > rowLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == contentArr || 0 == contentArr.length) {
			throw new XlsException("参数错误，没有可写的内容！");
		}
	}

	/**
	 * 检验参数是否合格
	 * 
	 * @param sheet
	 * @param colLocNum
	 * @param rowLocNum
	 * @param contentArr
	 */
	private static void CheckParams(WritableSheet sheet, int colLocNum, int rowLocNum, String[] contentArr) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > colLocNum || 0 > rowLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == contentArr || 0 == contentArr.length) {
			throw new XlsException("参数错误，没有可写的内容！");
		}
	}

	/**
	 * 读取工作表一行数据
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param rowLocNum
	 *            起始位置行序号(从0开始)
	 * @param callback
	 *            读取到行内容时执行的回调接口
	 * @return
	 */
	public static boolean readRow(Sheet sheet, int rowLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > rowLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		if (!callback.preCallRowOrColumn()) {
			return false;
		}
		Cell[] row = sheet.getRow(rowLocNum);
		for (Cell cell : row) {
			if (!callback.callCell(cell)) {
				break;
			}
		}
		return callback.afterCallRowOrColumn();
	}

	/**
	 * 读取工作表多行数据
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param startRowLocNum
	 *            起始位置行序号(从0开始)
	 * @param endRowLocNum
	 *            结束位置行序号(从0开始)
	 * @param callback
	 *            读取到行内容时执行的回调接口
	 */
	public static void readRows(Sheet sheet, int startRowLocNum, int endRowLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > startRowLocNum || startRowLocNum > endRowLocNum || 0 > endRowLocNum) {
			throw new XlsException("参数错误，起始或结束位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		for (int i = startRowLocNum; i < endRowLocNum + 1; i++) {
			if (!readRow(sheet, i, callback)) {
				break;
			}
		}
	}

	/**
	 * 读取工作表多行数据，从某一行开始读取到结束行
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param startRowLocNum
	 *            起始位置行序号(从0开始)
	 * @param callback
	 *            读取到行内容时执行的回调接口
	 */
	public static void readRows(Sheet sheet, int startRowLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > startRowLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		// 获取内容
		for (int i = startRowLocNum; i < sheet.getRows(); i++) {
			if (!readRow(sheet, i, callback)) {
				break;
			}
		}
	}
	
	/**
	 * 读取工作表一列数据
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param colLocNum
	 *            起始位置行序号(从0开始)
	 * @param callback
	 *            读取到列内容时执行的回调接口
	 * @return
	 */
	public static boolean readColumn(Sheet sheet, int colLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > colLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		if (!callback.preCallRowOrColumn()) {
			return false;
		}
		Cell[] column = sheet.getColumn(colLocNum);
		for (Cell cell : column) {
			if (!callback.callCell(cell)) {
				break;
			}
		}
		return callback.afterCallRowOrColumn();
	}
	
	/**
	 * 读取工作表多列数据
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param startColLocNum
	 *            起始位置列序号(从0开始)
	 * @param endColLocNum
	 *            结束位置列序号(从0开始)
	 * @param callback
	 *            读取到列内容时执行的回调接口
	 */
	public static void readColumns(Sheet sheet, int startColLocNum, int endColLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > startColLocNum || startColLocNum > endColLocNum || 0 > endColLocNum) {
			throw new XlsException("参数错误，起始或结束位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		for (int i = startColLocNum; i < endColLocNum + 1; i++) {
			if (!readColumn(sheet, i, callback)) {
				break;
			}
		}
	}
	
	/**
	 * 读取工作表多列数据，从某一列开始读取到结束列
	 * 
	 * @param sheet
	 *            读取的工作表
	 * @param startColLocNum
	 *            起始位置列序号(从0开始)
	 * @param callback
	 *            读取到列内容时执行的回调接口
	 */
	public static void readColumns(Sheet sheet, int startColLocNum, ExcelParseCallback callback) {
		if (null == sheet) {
			throw new XlsException("参数错误，没有可用的工作表！");
		}
		if (0 > startColLocNum) {
			throw new XlsException("参数错误，起始位置有误！");
		}
		if (null == callback) {
			throw new XlsException("参数错误，没有可用的回调接口实现！");
		}
		// 获取内容
		for (int i = startColLocNum; i < sheet.getColumns(); i++) {
			if (!readRow(sheet, i, callback)) {
				break;
			}
		}
	}

	public static void main(String[] args) throws BiffException, IOException {
		// 读取excel文件，获取工作簿
		Workbook workbook = Workbook.getWorkbook(new File("d:/user.xls"));
		// 获取第一个工作表
		Sheet sheet = workbook.getSheet(0);
		// 获取第一行标题
		Cell[] row = sheet.getRow(100000);
		StringBuilder sb = new StringBuilder();
		for (Cell cell : row) {
			sb.append(cell.getContents()).append(',');
		}
		sb.deleteCharAt(sb.length() - 1);
		System.out.println(sb.toString());

	}
}
